/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2002 Copyright (C)
 *
 *  File: nim_st6110.c
 *
 *  Description: This file contains STV6110 basic function in LLD.
 *
 *  History:
 *      Date        Author      Version  Comment
 *      ====        ======      =======  =======
 *  1.  2006.11,7      wattliu     0.1.000  Initial
 *
 ****************************************************************************/
#include <sys_config.h>
#include <retcode.h>
#include <types.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <bus/i2c/i2c.h>
#include <osal/osal.h>
#include "nim_stv6110.h"

#define STV6110_PRINTF(...)
//#define STV6110_PRINTF	libc_printf

static unsigned char init_data[] = {0x00, 0x07,0x11,0xdc,0x85,0x17,0x07,0xec,0x1e}; 

struct QPSK_TUNER_CONFIG_EXT * stv6110_dev_id[MAX_TUNER_SUPPORT_NUM] = {NULL};
static UINT32 stv6110_tuner_cnt = 0;

INT32 nim_stv6110_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
{
	INT32 result;
	struct QPSK_TUNER_CONFIG_EXT * stv6110_ptr = NULL;
	
	/* check Tuner Configuration structure is available or not */
	if (ptrTuner_Config == NULL||stv6110_tuner_cnt>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stv6110_ptr = (struct QPSK_TUNER_CONFIG_EXT *)MALLOC(sizeof(struct QPSK_TUNER_CONFIG_EXT));
	if(!stv6110_ptr)
	      return ERR_FAILUE;
	MEMCPY(stv6110_ptr, ptrTuner_Config, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	stv6110_dev_id[stv6110_tuner_cnt] = stv6110_ptr;
	*tuner_id = stv6110_tuner_cnt;
	stv6110_tuner_cnt++;
	if ((result = i2c_write(stv6110_ptr->i2c_type_id, stv6110_ptr->cTuner_Base_Addr, init_data, 9)) != SUCCESS)
	{
		STV6110_PRINTF("nim_stv6110_init: I2C write error\n");
		return result;
	}

	return SUCCESS;
}

INT32 nim_stv6110_control(UINT32 tuner_id,UINT32 freq, UINT32 sym)
{
	UINT16 divider =0;
	UINT32 bs,i,k,j ;
	UINT16 n_div;
	UINT8 temp,p_div, r_div, f_step, cf;
	UINT8  m_cBR, m_cBF, m_cReg7, m_cReg13;	
	INT32 iFbw_3db,  m_iFbw_3db;	
	UINT8 data[16],data_1,data_cp[20],data_tmp[20];
	float fTemp;
	UINT8 result;

	struct QPSK_TUNER_CONFIG_EXT * stv6110_ptr = NULL;
	if(tuner_id>=stv6110_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stv6110_ptr = stv6110_dev_id[tuner_id];
	data[0] = 0x00; // sub register address;

    	if (freq < 950)
		freq = 950;
    	else if (freq > 2160)
		freq = 2160;

	if (sym ==0)
		bs = 45000;
	else if (sym > 45000)
		bs = 45000;
	else
		bs = sym;

	// calibrate 1M frequency, 0 is for 16MHz crystal
	data[1] = 0x07;
	// bb gain, 4 is 8db
	data[2] = 0x14;

	n_div = freq;
	data[3] = n_div & 0xff;
	if(freq<1024)
		data[4] = (0x50 | (n_div>>8) & 0x0f);
	else if(freq<1300)
		data[4] = (0x70 | (n_div>>8) & 0x0f);
	else if(freq<2048)
		data[4] = (0x80 | (n_div>>8) & 0x0f);
	else
		data[4] = (0xa0 | (n_div>>8) & 0x0f);

	iFbw_3db = bs*135 / 200;               	// rolloff is 35%
	iFbw_3db = iFbw_3db*130/100;                    // 0.1dB to 3dB need about 30% transition band
	if (bs<6500)  iFbw_3db = iFbw_3db + 3000;     // add 3M when Rs<6.5M
	iFbw_3db = iFbw_3db + 2000;                  // add 2M for LNB frequency shifting
	iFbw_3db = iFbw_3db*108/100;                   // add 8% margin since fc is not very accurate
	if (iFbw_3db< 5000)   iFbw_3db =  5000;           // Maxim LPF can be tuned form 5M to 36M, step is 1M
	if (iFbw_3db>36000)   iFbw_3db = 36000;           // Maxim LPF can be tuned form 5M to 36M, step is 1M

	cf = iFbw_3db/1000 - 5;

	if(cf >0x1f)
		cf = 0x1f;
	data[5] = cf & 0xff;
	data[6] = 0x06; // Start VCO calibration and LPF calibration
	data[7] = 0x00;
	data[8] = 0x00;

	if ((result = i2c_write(stv6110_ptr->i2c_type_id, stv6110_ptr->cTuner_Base_Addr, data, 7)) != SUCCESS)
	{
		STV6110_PRINTF("STV6110: I2C write error\n");
		return result;
	}
}

INT32 nim_stv6110_status(UINT32 tuner_id,UINT8 *lock)
{
	INT32 result;
	UINT8 data;

	struct QPSK_TUNER_CONFIG_EXT * tuner_dev_ptr = NULL;
	if(tuner_id>=stv6110_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
	{
		*lock = 0;
		return ERR_FAILUE;
	}
	
	data = 0x05;//state register
	tuner_dev_ptr = stv6110_dev_id[tuner_id];
	if ((result = i2c_write_read(tuner_dev_ptr->i2c_type_id, tuner_dev_ptr->cTuner_Base_Addr, &data, 1,1)) == SUCCESS)
	{
		STV6110_PRINTF("nim_stv6110_status: data = 0x%x\n", data);
		*lock = data &0x01;
	}

	return result;
}

